/* ************************************************************
 *  _harrisQue.hpp 
 *  
 * ************************************************************/
#ifndef HARRIS_QUE_HPP
#define HARRIS_QUE_HPP

#include <pthread.h>
#include <exception>
#include <list>


using namespace std;

template <class Type>
class AndroidQueue
{
public:
	AndroidQueue();
	~AndroidQueue();
    	class ReadEmptyQueue : public exception {
      	public:
        	virtual const char* what() const throw() {
            		return "read empty queue";
        	}
    	};
    	int size() ; 
    	bool isEmpty() const; 
    	void enQueue (const Type& elem); 
    	Type deQueue (); 
    	Type& front ();
	int queWait(int ttl);
	int queSignal();
private:
    list<Type> _harrisQue;        // container for the elements
	pthread_mutex_t mtx;
	pthread_cond_t cv;
	struct timespec to;
 
};
	// - IMPL - 
template <class Type>
AndroidQueue<Type>::AndroidQueue()
{
        int mut = pthread_mutex_init(&mtx, NULL);
        int cva = pthread_cond_init(&cv,NULL);
        if(mut || cva) {
                //cout <<"Error AndroidQueue():\n\tQueMut:"<<mut<<"\n\tQueCva:"<<cva<<endl;
                abort();
        }
}

template <class Type>
AndroidQueue<Type>::~AndroidQueue()
{
        pthread_cond_destroy(&cv);
}
 
	// number of elements
template <class Type>
int AndroidQueue<Type>::size() {
	pthread_mutex_lock( &mtx );
     	int sz = _harrisQue.size();
	pthread_mutex_unlock(&mtx );
     	return sz;
}

	// is queue empty?
template <class Type>
bool AndroidQueue<Type>::isEmpty() const {
	pthread_mutex_lock( &mtx );
      	bool rst = _harrisQue.empty();
	pthread_mutex_unlock(&mtx );
	return rst;
}

	// insert element into the queue
template <class Type>
void AndroidQueue<Type>::enQueue (const Type& elem) 
{
	int ret = pthread_mutex_lock( &mtx );
	if(ret != 0) {
		//cout <<"\tError blocking on QueMutex : "<<ret<<endl;
		return;
	}
                        
	_harrisQue.push_back(elem);
	if((ret = pthread_cond_signal(&cv)) != 0) {
		//cout <<"\tError enQueue()::cond_signal cv : "<<ret<<endl;
		return;
	}
	pthread_mutex_unlock(&mtx );
}

// read element from the queue and return its value
template <class Type>
Type AndroidQueue<Type>::deQueue () 
{
	pthread_mutex_lock( &mtx );	
      	if (_harrisQue.empty()) {
       		throw ReadEmptyQueue();
      	}
      	Type elem(_harrisQue.front());
       	_harrisQue.pop_front();
	pthread_mutex_unlock(&mtx );
        //cout <<"..AdipMsgQue::pop("<<time(0)<<") --------"<<endl;
       	return elem;
}

    	// return value of next element
template <class Type>
Type& AndroidQueue<Type>::front () {
       	if (_harrisQue.empty()) {
       		throw ReadEmptyQueue();
      	}
      	return _harrisQue.front();
}
	// make queue access thread sage
template <class Type>
int AndroidQueue<Type>::queWait(int ttl)
{
        int a = pthread_mutex_lock(&mtx);
        to.tv_sec = time(0) + ttl;
        to.tv_nsec = 0;

        int b = pthread_cond_timedwait(&cv, &mtx, &to);
        int c = pthread_mutex_unlock(&mtx);
	if(a || c) {
		//cout <<" Could not wait on a:"<<a<<" b:"<<c<<"...."<<endl;
	}
        return b;
}

	// make queue access thread sage
template <class Type>
int AndroidQueue<Type>::queSignal()
{
        int a = pthread_mutex_lock(&mtx);
        int b = pthread_cond_signal(&cv);
        int c = pthread_mutex_unlock(&mtx);
	if(a || c) {
		//cout <<" Could not wake those on wait a:"<<a<<" b:"<<c<<"...."<<endl;
	}
        return b;
}

#endif /* HARRIS_QUE_HPP */
